package xcmg.device.service.purchase;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageInfo;
import org.apache.poi.ss.usermodel.CellType;
import yb.ecp.fast.infra.util.PageHelperPlus;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.PurchaseDictionaryDO;
import xcmg.device.dao.entity.basic.MaterialsPurchaseInfo;
import xcmg.device.dao.entity.company.CompanyInfoDO;
import xcmg.device.dao.entity.purchase.BuyPlanDO;
import xcmg.device.dao.entity.purchase.BuyPlanDetailDO;
import xcmg.device.dao.entity.purchase.PurchasePlanDO;
import xcmg.device.dao.mapper.BuyPlanDetailMapper;
import xcmg.device.dao.mapper.BuyPlanMapper;
import xcmg.device.dao.mapper.CompanyInfoMapper;
import xcmg.device.dao.mapper.PurchasePlanMapper;
import xcmg.device.dao.mapper.agent.ServiceBasicDataAgentMapper;
import xcmg.device.dao.mapper.basic.MaterialsPurchaseInfoMapper;
import xcmg.device.infra.DateUtil;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.ExportUtil;
import xcmg.device.infra.FileUtil;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.service.GenDocumentService;
import xcmg.device.service.basic.MaterialsService;
import xcmg.device.service.basic.PurchaseDictionaryService;
import xcmg.device.service.vo.FunctionResult;
import xcmg.device.service.vo.basic.MaterialsVO;
import xcmg.device.service.vo.basic.PurchaseDictionaryVO;
import xcmg.device.service.vo.purchase.BuyPlanAddVO;
import xcmg.device.service.vo.purchase.BuyPlanDetailVO;
import xcmg.device.service.vo.purchase.BuyPlanReportVO;
import xcmg.device.service.vo.purchase.BuyPlanSupplierVO;
import xcmg.device.service.vo.purchase.BuyPlanVO;
import xcmg.device.service.warehouse.CommonService;
import xcmg.device.util.CompanyUtil;
import xcmg.device.util.DecimalUtil;
import xcmg.device.util.LocalDateTimeUtil;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.infra.log.LogHelper;
import yb.ecp.fast.infra.util.ListUtil;
import yb.ecp.fast.infra.util.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class BuyPlanService {

    @Autowired
    private BuyPlanMapper buyPlanMapper;

    @Autowired
    private BuyPlanDetailMapper buyPlanDetailMapper;

    @Autowired
    private PurchasePlanMapper purchasePlanMapper;

    @Autowired
    private FastGenClient fastGenClient;

    @Autowired
    private GenDocumentService genDocumentService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private CompanyInfoMapper companyInfoMapper;

    @Autowired
    private MaterialsService materialsService;

    @Autowired
    private BuyPlanUpdateService buyPlanUpdateService;
    @Autowired
    private ServiceBasicDataAgentMapper serviceBasicDataAgentMapper;

    @Autowired
    private ObjectMapper objectMapper;

    @Value("${spring.file.download.path}")
    private String filePath;

    private  String templateExcelFileName="BuyPlanImport.xls";

    private String buyPlanTemplateFileName = "BuyPlan.xls";

    @Autowired
    private PurchaseDictionaryService purchaseDictionaryService;

    @Autowired
    private MaterialsPurchaseInfoMapper materialsPurchaseInfoMapper;

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode add(BuyPlanAddVO buyPlanAddVO)throws Exception{
        if(buyPlanAddVO.getHeaderInfo() == null || ListUtil.isNullOrEmpty(buyPlanAddVO.getMaterialList())){
            return ErrorCode.IllegalArument;
        }
        ActionResult<String> textResult = fastGenClient.textGuid();
        if (textResult.getCode() != ErrorCode.Success.getCode()) {
            return ErrorCode.IllegalArument;
        }

        BuyPlanDO buyPlanDO = new BuyPlanDO();
        BeanUtils.copyProperties(buyPlanAddVO.getHeaderInfo(), buyPlanDO);
        buyPlanDO.setId(textResult.getValue());
        buyPlanDO.setPlanOrder(genDocumentService.getDocumentNo(BillDesc.BuyPlan));
        buyPlanDO.setCreateDate(new Date());
        boolean success;

        PurchasePlanDO purchasePlanDO = new PurchasePlanDO();
        for(BuyPlanDetailVO detailVO : buyPlanAddVO.getMaterialList()){
            BuyPlanDetailDO detailDO = new BuyPlanDetailDO();
            BeanUtils.copyProperties(detailVO, detailDO);
            detailDO.setBillId(buyPlanDO.getId());
            success = buyPlanDetailMapper.insert(detailDO)>0;
            if(!success){
                throw new Exception("操作失败");
            }

            //更新采购计划报表的计划未执行数量
            if(!StringUtil.isNullOrEmpty(detailDO.getSourceOrder())){
                purchasePlanDO.setBillNo(detailDO.getSourceOrder());
                purchasePlanDO.setMaterialsNo(detailDO.getMaterialsNo());
                purchasePlanDO.setPlanAmount(detailDO.getQty());
                purchasePlanMapper.updateByBillNoAndMaterialsNo(purchasePlanDO);
            }
        }
        success = buyPlanMapper.insert(buyPlanDO)>0;
        if(!success){
            throw new Exception("操作失败");
        }
        return ErrorCode.Success;
    }

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode update(BuyPlanAddVO buyPlanAddVO) throws Exception{
        if(buyPlanAddVO.getHeaderInfo() == null || ListUtil.isNullOrEmpty(buyPlanAddVO.getMaterialList())){
            return ErrorCode.IllegalArument;
        }
        if(buyPlanAddVO.getHeaderInfo().getSendStatus() > 0){
            throw new Exception("该回购单已建入库单，无法修改");
        }
        BuyPlanDO buyPlanDO = new BuyPlanDO();
        BeanUtils.copyProperties(buyPlanAddVO.getHeaderInfo(), buyPlanDO);
        if(buyPlanDO.getAuditStatus() == 2){
            buyPlanDO.setAuditStatus(0);
        }
        boolean success = buyPlanDetailMapper.deleteByBillId(buyPlanDO.getId()) > 0;
        if(!success){
            throw new Exception("操作失败");
        }

        for(BuyPlanDetailVO detailVO : buyPlanAddVO.getMaterialList()){
            BuyPlanDetailDO detailDO = new BuyPlanDetailDO();
            BeanUtils.copyProperties(detailVO, detailDO);
            detailDO.setBillId(buyPlanDO.getId());
            success = buyPlanDetailMapper.insert(detailDO)>0;
            if(!success){
                throw new Exception("操作失败");
            }
        }

        success = buyPlanMapper.update(buyPlanDO) > 0;
        if(!success){
            throw new Exception("操作失败");
        }

        return ErrorCode.Success;
    }

    public PageCommonVO list(SearchCommonVO<BuyPlanVO> condition) {
        PageCommonVO<BuyPlanVO> pageCommonVO = new PageCommonVO();
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<BuyPlanDO> doList = buyPlanMapper.list(condition.getFilters());
        List<BuyPlanVO> voList = new ArrayList<>();
        for (BuyPlanDO entity : doList) {
            BuyPlanVO model = new BuyPlanVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        pageCommonVO.setPageInfo(new PageInfo(doList));
        pageCommonVO.setPageInfoList(voList);
        return pageCommonVO;
    }

    public PageCommonVO autoCreatePlanLists(SearchCommonVO<BuyPlanVO> condition) {
        PageCommonVO<BuyPlanVO> pageCommonVO = new PageCommonVO();
        PageHelperPlus.orderBy("AUDIT_DATE desc nulls last,create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<BuyPlanDO> doList = buyPlanMapper.list(condition.getFilters());
        List<BuyPlanVO> voList = new ArrayList<>();
        for (BuyPlanDO entity : doList) {
            BuyPlanVO model = new BuyPlanVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        pageCommonVO.setPageInfo(new PageInfo(doList));
        pageCommonVO.setPageInfoList(voList);
        return pageCommonVO;
    }

    public PageCommonVO reportList(SearchCommonVO<BuyPlanReportVO> condition) {
        PageCommonVO<BuyPlanReportVO> pageCommonVO = new PageCommonVO();
        PageHelperPlus.orderBy("MATERIALS_NO DESC");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        condition.getFilters().setMaterialsList(xcmg.device.infra.StringUtil.splitList(condition.getFilters().getMaterialsNos()));
        List<BuyPlanReportVO> voList = buyPlanMapper.planReportList(condition.getFilters());
        pageCommonVO.setPageInfo(new PageInfo(voList));
        pageCommonVO.setPageInfoList(voList);
        return pageCommonVO;
    }

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode delete(List<String> ids) throws Exception{
        int num = buyPlanMapper.findForDeleteByIds(ids);
        if(num > 0){
            throw new Exception("已经审核通过的采购计划单不能删除");
        }
        return buyPlanMapper.updateDel(ids, 1)>0?ErrorCode.Success:ErrorCode.Failure;
    }

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode audit(BuyPlanVO buyPlanVO, String userId) throws Exception{
        BuyPlanDO buyPlanDO = new BuyPlanDO();
        BeanUtils.copyProperties(buyPlanVO, buyPlanDO);
        buyPlanDO.setAuditId(userId);
        buyPlanDO.setAuditName(commonService.getUserName(userId));
        buyPlanDO.setAuditDate(new Date());
        return buyPlanMapper.update(buyPlanDO)>0?ErrorCode.Success:ErrorCode.Failure;
    }

    public BuyPlanAddVO item(String id){
        BuyPlanAddVO result = new BuyPlanAddVO();
        BuyPlanDO buyPlanDO = buyPlanMapper.selectByPrimaryKey(id);
        if(buyPlanDO == null){
            return result;
        }
        BuyPlanVO buyPlanVO = new BuyPlanVO();
        BeanUtils.copyProperties(buyPlanDO, buyPlanVO);
        result.setHeaderInfo(buyPlanVO);
        List<BuyPlanDetailVO> listVO = new ArrayList<>();
        List<BuyPlanDetailDO> listDO = buyPlanDetailMapper.list(id);
        for(BuyPlanDetailDO entity:listDO){
            BuyPlanDetailVO model = new BuyPlanDetailVO();
            BeanUtils.copyProperties(entity, model);
            listVO.add(model);
        }
        result.setMaterialList(listVO);
        return result;
    }

    public BuyPlanAddVO itemForPurchase(String id,String purchaseGroup,String orgId){
        BuyPlanAddVO result = new BuyPlanAddVO();
        BuyPlanDO buyPlanDO = buyPlanMapper.selectByPrimaryKey(id);
        if(buyPlanDO == null){
            return result;
        }
        CompanyInfoDO companyInfoDO = companyInfoMapper.item(buyPlanDO.getOrgId());
        String sapCode = companyInfoDO.getSapCode();

        BuyPlanVO buyPlanVO = new BuyPlanVO();
        BeanUtils.copyProperties(buyPlanDO, buyPlanVO);
        result.setHeaderInfo(buyPlanVO);
        //add by wangzhaoyu  20201203获取用户配置的采购组，用于前端自动填充http://10.90.1.198/zentao/story-view-2412.html
        String userPurchaseGroup = getPurchaseGroup(purchaseGroup, orgId);
        result.getHeaderInfo().setUserPurchaseGroup(userPurchaseGroup);

        List<BuyPlanDetailVO> listVO = new ArrayList<>();
        List<BuyPlanDetailDO> listDO = buyPlanDetailMapper.listGroup(id);
        for(BuyPlanDetailDO entity:listDO){
            BuyPlanDetailVO model = new BuyPlanDetailVO();
            BeanUtils.copyProperties(entity, model);
            //需求改造：http://10.90.1.198/zentao/story-view-2963.html
            // 为了减少对原始逻辑的影响，增加判断 如果是随车，并且详情中的交货日期字段有值则将此值赋值
            Date deliveryDate = entity.getDeliveryDate();
            if((CompanyUtil.isSCSapCode(sapCode)||CompanyUtil.isWJSapCode(sapCode)) && deliveryDate != null){
                model.setDeliveryDate(deliveryDate);
            }else{
                model.setDeliveryDate(LocalDateTimeUtil.plusDays(model.getDeliverySpend()));
            }
            listVO.add(model);
        }
//        getMaterialsPurchaseInfoFromSap(sapCode, listVO, buyPlanVO);
        buyPlanUpdateService.saveOrUpdatePurchaseInfo(listVO, buyPlanDO.getOrgId());
        result.setMaterialList(listVO);
        return result;
    }


    private String getPurchaseGroup(String userPurchaseGroup,String orgId){
        //如果当前登陆人采购组不为空则去字典表中查询当前登陆人的采购组是否能匹配到，如果匹配不到返回空，否则返回当前登陆人的采购组
        if(StringUtils.isEmpty(userPurchaseGroup)){
            return null;
        }
        //
        int purchasegroup = serviceBasicDataAgentMapper.getCodeCount(orgId, "PURCHASEGROUP", userPurchaseGroup);
        if(purchasegroup > 0){
            return userPurchaseGroup;
        }
        return null;
    }

    private void saveOrUpdatePurchaseInfo(List<MaterialsPurchaseInfo> purchaseInfos, String orgId, String materialsNo) {
        materialsPurchaseInfoMapper.delete(orgId, materialsNo);
        for (MaterialsPurchaseInfo purchaseInfo : purchaseInfos) {
            try {
                purchaseInfo.setOrgId(orgId);
                materialsPurchaseInfoMapper.insert(purchaseInfo);
            } catch (Exception e) {
                // nothing
            }
        }
    }

    public void export(List<String> ids)throws Exception{
        invokeExport(buyPlanMapper.findByIds(ids));
    }

    public void exportAll(BuyPlanVO condition)throws Exception{
        Integer count = buyPlanMapper.listCount(condition);
        List<BuyPlanDO> dataList = new ArrayList<>();
        int times = count/500+1;
        for(int i=0; i<times; i++){
            PageHelperPlus.startPage(i + 1, 500, "create_date desc");
            dataList.addAll(buyPlanMapper.list(condition));
        }
        invokeExport(dataList);
    }

    private void invokeExport(List<BuyPlanDO> doList)throws Exception{
        String title = "采购计划单数据导出";
        String[] rowsName = new String[]{"序号", "采购计划单号", "申请人", "申请部门", "申请时间", "采购方式",
                "备注", "审核人", "审核时间", "审核状态", "审核意见","是否创建采购单"};
        List<Object[]>  dataList = new ArrayList<>();
        Object[] objs;
        for (int i = 0; i < doList.size(); i++) {
            BuyPlanDO exportDO = doList.get(i);
            objs = new Object[rowsName.length];
            objs[0] = i+1;
            objs[1] = exportDO.getPlanOrder();
            objs[2] = exportDO.getCreateName();
            objs[3] = exportDO.getDeptName();
            objs[4] = DateUtil.formatDateTime(exportDO.getCreateDate());
            objs[5] = exportDO.getTypeDesc();
            objs[6] = exportDO.getNote();
            objs[7] = exportDO.getAuditName();
            objs[8] = DateUtil.formatDateTime(exportDO.getAuditDate());
            objs[9] = getAuditState(exportDO.getAuditStatus());
            objs[10] = exportDO.getAuditNote();
            objs[11] = exportDO.getSendStatus()==null?"否":(exportDO.getSendStatus()==0?"否":"是");
            dataList.add(objs);
        }
        ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
        exportUtil.export(response);
    }

    private String getAuditState(Integer state){
        switch (state){
            case 0:
                return "未审核";
            case 1:
                return "审核拒绝";
            case 2:
                return "审核通过";
            default:
                return "未审核";
        }
    }

//    private void getMaterialsPurchaseInfoFromSap(String sapCode, List<BuyPlanDetailVO> planDetailList, BuyPlanVO buyPlanVO) {
//        if (CollectionUtils.isEmpty(planDetailList)) {
//            return;
//        }
//        Map<String, BuyPlanDetailVO> planDetailMap = new HashMap<>(128);
//        ImportParam importParam = new ImportParam();
//        Map<String, String> map = new HashMap<>(16);
//        map.put("WERKS", sapCode);
//        importParam.setFunction("ZPMSBJ_GET_INFORMATION");
//        importParam.setCommonParamMap(map);
//
//        Map<String, List<Map<String, String>>> tableParamMap = new HashMap<>(16);
//        List<Map<String, String>> list = new ArrayList<>();
//
//        Map<String, String> mapd;
//        for (BuyPlanDetailVO detailDO : planDetailList) {
//            mapd = new HashMap<>();
//            mapd.put("MATNR", detailDO.getMaterialsNo());
//            list.add(mapd);
//
//            planDetailMap.put(detailDO.getMaterialsNo(), detailDO);
//        }
//        tableParamMap.put("MATNR_IN", list);// 传入内表
//        importParam.setTableParamMap(tableParamMap);
//        importParam.setTable("PURINFOOUT");// 传出内表
//        importParam.setSapCode(sapCode);
//        OutputParam outputParam = SAPCommonUtil.getData(importParam);
//        if (null == outputParam || outputParam.getCode() != 0) {
//            LogHelper.error("sap返回值为null", ErrorCode.RequestIdError.getCode());
//            return;
//        }
//
//        List<Map<String, String>> outDataList = outputParam.getDataList();
//        if (CollectionUtils.isEmpty(outDataList)) {
//            return;
//        }
//        assemblyPurchaseInfo(outDataList, planDetailMap, buyPlanVO);
//    }


    private List<MaterialsPurchaseInfo> assemblyPurchaseInfo(List<Map<String, String>> dataList, Map<String,BuyPlanDetailVO> planDetailMap, BuyPlanVO buyPlanVO) {
        List<MaterialsPurchaseInfo> purchaseInfoVOS = new ArrayList<>();
        Date now = new Date();
        Map<String, String> suppliersMap = new HashMap<>(128);
        for (Map<String, String> resultMap : dataList) {
            MaterialsPurchaseInfo purchaseInfo = new MaterialsPurchaseInfo();
            purchaseInfo.setMaterialsNo(resultMap.get("MATNR"));//零件号
            purchaseInfo.setMaterialsDes(resultMap.get("MAKTX"));//零件名称（短文本）
            purchaseInfo.setSupplierSapCode(resultMap.get("LIFNR"));//供应商或债权人的帐号
            purchaseInfo.setSupplierName(resultMap.get("NAME1"));//名称 1
            String price = resultMap.get("KBETR");//价格 (条件金额或百分数 )
            purchaseInfo.setPrice(StringUtils.isNotBlank(price)? new BigDecimal(price) : BigDecimal.ZERO);
            purchaseInfo.setPriceUnit(resultMap.get("KPEIN"));//条件定价单位
            purchaseInfo.setBaseUnit(resultMap.get("MEINS"));//基本计量单位

            String startTimeStr = resultMap.get("DATAB");//条件记录有效起始日
            String endTimeStr = resultMap.get("DATBI");//条件记录有效截止日期
            purchaseInfo.setStartTime(parseGMTDate(startTimeStr));
            purchaseInfo.setEndTime(parseGMTDate(endTimeStr));
            purchaseInfo.setRecordingNo(resultMap.get("KNUMH"));//条件记录号
            purchaseInfo.setIdentification(resultMap.get("EVERS"));//暂估标识
            purchaseInfo.setPurchaseSapCode(resultMap.get("EKORG"));//采购方sapCode
            purchaseInfo.setFactorySapCode(resultMap.get("WERKS"));//主机厂sapCode
            purchaseInfo.setRecordingCategory(resultMap.get("ESOKZ"));//采购信息记录分类
            String deliverySpend = resultMap.get("APLFZ");//交货期（交货所需时间）
            if (StringUtils.isNotBlank(deliverySpend)) {
                purchaseInfo.setDeliverySpend(new BigDecimal(deliverySpend));
            }
            purchaseInfo.setUpdateTime(now);
            purchaseInfoVOS.add(purchaseInfo);

            if (planDetailMap != null && buyPlanVO != null) {
                if(!suppliersMap.containsKey(purchaseInfo.getSupplierSapCode())){
                    suppliersMap.put(purchaseInfo.getSupplierSapCode(), purchaseInfo.getSupplierName());
                }
                BuyPlanDetailVO planDetailVO = planDetailMap.get(purchaseInfo.getMaterialsNo());
                if (planDetailVO != null) {
                    planDetailVO.getPurchaseInfoVOList().add(purchaseInfo);
                    buyPlanVO.getSupplierList().add(new BuyPlanSupplierVO(purchaseInfo.getSupplierSapCode(), purchaseInfo.getSupplierName()));
                    if(StringUtils.isBlank(planDetailVO.getSupplierCode())){
                        planDetailVO.setSupplierCode(purchaseInfo.getSupplierSapCode());
                        planDetailVO.setSupplierOrgName(purchaseInfo.getSupplierName());
                    }
                }
            }
        }
        return purchaseInfoVOS;
    }

    private Date parseGMTDate(String dateGMT){
        if (StringUtils.isBlank(dateGMT)) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss 'GMT+08:00' yyyy",Locale.US);
        try {
            return sdf.parse(dateGMT);
        } catch (ParseException e) {
            return null;
        }
    }

    public FunctionResult importExcel(InputStream in, String orgId) throws Exception {
        FunctionResult result = new FunctionResult();
        HSSFWorkbook wb = new HSSFWorkbook(in);
        HSSFSheet sheet = wb.getSheetAt(0);

        int totalRow = sheet.getLastRowNum();
        if (totalRow < 2) {
            result.setCode(ErrorCode.IllegalArument);
            result.setValue("导入模板不正确");
            return result;
        }
//        int totalCell = sheet.getRow(1).getLastCellNum();
//        if (totalCell != 4) {
//            result.setCode(ErrorCode.IllegalArument);
//            result.setValue("导入模板不正确");
//            return result;
//        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<BuyPlanReportVO> detailVOList = new ArrayList<>();
        List<BuyPlanReportVO> errorDetailVOList = new ArrayList<>();
        for (int i = 2; i <= totalRow; i++) {
            HSSFRow curRow = sheet.getRow(i);
            BuyPlanReportVO detailVO = new BuyPlanReportVO();
            if (curRow == null) {
                continue;
            }
            String materialsNo = getCellValue(curRow, 0);
            String qty = getCellValue(curRow, 2);
            String supplierName = getCellValue(curRow,3);
            if (StringUtil.isNullOrEmpty(materialsNo) && StringUtil.isNullOrEmpty(qty)) {
                continue;
            }
            String deliveryDateStr = getCellValue(curRow,4);
            Date deliveryDate = null;
            if(StringUtils.isNotEmpty(deliveryDateStr)){
                try{
                    deliveryDate = sdf.parse(deliveryDateStr);
                }catch (Exception e){
                    detailVO.setErrorRow(i + 1);
                    detailVO.setRemark("交货日期格式为yyyy-MM-dd");
                    errorDetailVOList.add(detailVO);
                    continue;
                }
            }
            if (StringUtil.isNullOrEmpty(materialsNo)) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("零件编码不能为空");
                errorDetailVOList.add(detailVO);
                continue;
            }
            if (StringUtil.isNullOrEmpty(qty)) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("计划数量不能为空");
                errorDetailVOList.add(detailVO);
                continue;
            }
            if (!isInteger(qty) || "0".equals(qty)) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("入库数量格式不正确");
                errorDetailVOList.add(detailVO);
                continue;
            }
            if (new BigDecimal(qty).compareTo(BigDecimal.valueOf(99999999.99)) > 0) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("申请数量过大");
                errorDetailVOList.add(detailVO);
                continue;
            }
            MaterialsVO materialsVO = materialsService.itemByNo(materialsNo, orgId);
            if (materialsVO == null) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("零件不存在");
                errorDetailVOList.add(detailVO);
                continue;
            }
            BuyPlanReportVO buyPlanReportVO = new BuyPlanReportVO();
            buyPlanReportVO.setPlanAmount(new BigDecimal(qty));
            buyPlanReportVO.setMaterialsNo(materialsVO.getMaterialsNo());
            buyPlanReportVO.setMaterialsDes(materialsVO.getMaterialsDes());
            buyPlanReportVO.setMaterialsType(materialsVO.getMaterialsType());
            buyPlanReportVO.setUnit(materialsVO.getUnit());
            buyPlanReportVO.setPrice(DecimalUtil.roundDecimal4Output(materialsVO.getStandardPrice()));
            buyPlanReportVO.setSupplierName(supplierName);
            //buyPlanReportVO.setPrice(DecimalUtil.roundDecimal4Output(materialsVO.getStandardPrice()));
            //单价不除以100
            buyPlanReportVO.setPrice(materialsVO.getStandardPrice() == null ? BigDecimal.ZERO : materialsVO.getStandardPrice() );
            buyPlanReportVO.setDeliveryDate(deliveryDate);
            detailVOList.add(buyPlanReportVO);
        }

        if (ListUtil.isNullOrEmpty(errorDetailVOList)) {
            result.setValue(detailVOList);
            result.setCode(ErrorCode.Success);
        } else {
            result.setValue(errorDetailVOList);
            result.setCode(ErrorCode.IllegalArument);
        }
        return result;
    }

    private boolean isInteger(String str) {
        if (null == str || "".equals(str)) {
            return false;
        }
        try {
            BigDecimal decimal = new BigDecimal(str);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    private String getCellValue(HSSFRow curRow, int i) {
        String value = "";
        if (curRow.getCell(i) != null) {
            curRow.getCell(i).setCellType(CellType.STRING);
            value = curRow.getCell(i).getStringCellValue();
        }
        return value;
    }

    public void download() throws Exception {
        FileUtil.downLoadFile(response, filePath, templateExcelFileName);
    }

    /**
     * @description 导入采购计划
     * @param in
     * @param orgId 企业ID
     * @param userId 用户ID
     * @param userName 用户名称
     * @param deptId 部门ID
     * @param deptName 部门名称
     * @return
     */
    public FunctionResult importBuyPlanExcel( InputStream in, String orgId, String userId, String userName, String deptId, String deptName )
            throws Exception
    {
        FunctionResult result = new FunctionResult();
        HSSFWorkbook wb = new HSSFWorkbook( in );
        HSSFSheet sheet = wb.getSheetAt( 0 );

        int totalRow = sheet.getLastRowNum();
        if (totalRow < 2)
        {
            result.setCode( ErrorCode.IllegalArument );
            result.setValue( "导入模板不正确" );
            return result;
        }
        int totalCell = sheet.getRow( 1 ).getLastCellNum();
        if (totalCell != 4)
        {
            result.setCode( ErrorCode.IllegalArument );
            result.setValue( "采购方式不可为空" );
            return result;
        }

        // 采购申请单零件详情集合
        List<BuyPlanDetailVO> detailVOList = new ArrayList<>();
        // 格式异常数据集合
        List<BuyPlanReportVO> errorDetailVOList = new ArrayList<>();
        // 采购申请对象
        BuyPlanVO headerInfo = new BuyPlanVO();

        // 校验采购方式
        checkPurchaseType( sheet, errorDetailVOList, headerInfo, orgId );
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String supplierName = "";
        for ( int i = 3; i <= totalRow; i++ )
        {
            HSSFRow curRow = sheet.getRow( i );
            BuyPlanReportVO detailVO = new BuyPlanReportVO();
            if (curRow == null)
            {
                continue;
            }
            // 零件编号
            String materialsNo = getCellValue( curRow, 0 );
            // 计划数量
            String qty = getCellValue( curRow, 2 );

            String remark = getCellValue(curRow, 3);

            supplierName = getCellValue(curRow,4);

            // 零件编号、计划数量、采购方式不能为空
            if (StringUtil.isNullOrEmpty( materialsNo ) && StringUtil.isNullOrEmpty( qty ))
            {
                continue;
            }
            //交货日期
            Date deliveryDate = null;
            String delvieryDateStr = getCellValue(curRow,5);
            if(StringUtils.isNotBlank(delvieryDateStr)){
                try{
                    deliveryDate = sdf.parse(delvieryDateStr);
                }catch (Exception e){
                    detailVO.setErrorRow( i + 1 );
                    detailVO.setRemark( "日期格式不正确" );
                    errorDetailVOList.add( detailVO );
                    continue;
                }
            }
            if (StringUtil.isNullOrEmpty( materialsNo ))
            {
                detailVO.setErrorRow( i + 1 );
                detailVO.setRemark( "零件编码不能为空" );
                errorDetailVOList.add( detailVO );
                continue;
            }
            if (StringUtil.isNullOrEmpty( qty ))
            {
                detailVO.setErrorRow( i + 1 );
                detailVO.setRemark( "计划数量不能为空" );
                errorDetailVOList.add( detailVO );
                continue;
            }

            if (!isInteger( qty ) || "0".equals( qty ))
            {
                detailVO.setErrorRow( i + 1 );
                detailVO.setRemark( "入库数量格式不正确" );
                errorDetailVOList.add( detailVO );
                continue;
            }
            if (new BigDecimal( qty ).compareTo( BigDecimal.valueOf( 99999999.99 ) ) > 0)
            {
                detailVO.setErrorRow( i + 1 );
                detailVO.setRemark( "申请数量过大" );
                errorDetailVOList.add( detailVO );
                continue;
            }
            MaterialsVO materialsVO = materialsService.itemByNo( materialsNo, orgId );
            if (materialsVO == null)
            {
                detailVO.setErrorRow( i + 1 );
                detailVO.setRemark( "零件不存在" );
                errorDetailVOList.add( detailVO );
                continue;
            }

            // 将 采购申请单详情对象 放到集合中
            detailVOList.add( initBuyPlanDetailVO( materialsVO, qty, remark,supplierName ,deliveryDate) );
        }

        List<BuyPlanDetailVO> detailGroupList = new ArrayList<>();
        Map<String, List<BuyPlanDetailVO>> listMap = detailVOList.stream().collect(Collectors.groupingBy(BuyPlanDetailVO::getMaterialsNo));
        for (String materialNo : listMap.keySet()) {
            BuyPlanDetailVO buyPlanDetailVO = new BuyPlanDetailVO();
            BuyPlanDetailVO vo = listMap.get(materialNo).get(0);
            BeanUtils.copyProperties(vo,buyPlanDetailVO);
            buyPlanDetailVO.setQty(listMap.get(materialNo).stream().map(BuyPlanDetailVO::getQty).reduce(BigDecimal.ZERO,BigDecimal::add));
            //buyPlanDetailVO.setSupplierName(supplierName);
            detailGroupList.add(buyPlanDetailVO);
        }

        // 设置采购申请对象信息
        //headerInfo.setAuditStatus( 1 );
        //headerInfo.setAuditDate( applyDate );
        headerInfo.setDeptId( deptId );
        headerInfo.setDeptName( deptName );
        headerInfo.setCreateId( userId );
        headerInfo.setCreateName( userName );
        headerInfo.setCreateDate( new Date() );
        //headerInfo.setSupplierName(supplierName);
        // 企业ID
        headerInfo.setOrgId( orgId );

        BuyPlanAddVO buyPlanAddVO = new BuyPlanAddVO();
        // 设置采购申请单详情集合
        buyPlanAddVO.setMaterialList( detailGroupList );
        // 设置采购采购申请单对象
        buyPlanAddVO.setHeaderInfo( headerInfo );

        // 添加导入数据（只有全部校验通过，才能添加采购计划）
        ErrorCode errorCode = ErrorCode.Success;
        if (errorDetailVOList.isEmpty()) {
            errorCode = add(buyPlanAddVO);
        }

        // 判断校验和添加数据入库是否全部成功
        if (ListUtil.isNullOrEmpty( errorDetailVOList ) && errorCode.equals( ErrorCode.Success ))
        {
            result.setValue( detailVOList );
            result.setCode( ErrorCode.Success );
        }
        else
        {
            result.setValue( errorDetailVOList );
            result.setCode( ErrorCode.IllegalArument );
        }
        return result;
    }

    /**
     * @description 根据导入的信息生成采购申请单详情对象
     * @param materialsVO 基础零件信息对象
     * @param qty 零件数量
     * @return 采购申请单详情对象
     */
    private BuyPlanDetailVO initBuyPlanDetailVO( MaterialsVO materialsVO, String qty,String remark, String supplierName ,Date deliveryDate)
    {
        BuyPlanDetailVO buyPlanDetailVO = new BuyPlanDetailVO();
        // 零件编码
        buyPlanDetailVO.setMaterialsNo( materialsVO.getMaterialsNo() );
        // 零件名称
        buyPlanDetailVO.setMaterialsDes( materialsVO.getMaterialsDes() );
        // 零件类型
        buyPlanDetailVO.setMaterialsType( materialsVO.getMaterialsType() );
        // 零件单位
        buyPlanDetailVO.setUnit( materialsVO.getUnit() );
        // 单价
        //buyPlanDetailVO.setPrice( DecimalUtil.roundDecimal4Output( materialsVO.getStandardPrice() ) );
        //单价不除以100
        buyPlanDetailVO.setPrice(materialsVO.getStandardPrice() == null ? BigDecimal.ZERO : materialsVO.getStandardPrice() );
        // 零件数量
        buyPlanDetailVO.setQty( new BigDecimal( qty ) );
        // 零件总价
        buyPlanDetailVO.setTotalPrice( new BigDecimal( buyPlanDetailVO.getPrice().intValue() * buyPlanDetailVO.getQty().doubleValue() ) );
        // 采购组
        buyPlanDetailVO.setPurchaseGroup( materialsVO.getPurchaseGroup() );
        // 替换零件编码
        buyPlanDetailVO.setReplaceMaterialsNo( materialsVO.getReplaceMaterialsNo() );
        // 替换零件名称
        buyPlanDetailVO.setReplaceMaterialsDes( materialsVO.getReplaceMaterialsDes() );
        // 计划员ID
        buyPlanDetailVO.setPlannerId( materialsVO.getPlannerId() );
        // 计划员名称
        buyPlanDetailVO.setPlannerName( materialsVO.getPlannerName() );

        buyPlanDetailVO.setRemark(remark);

        buyPlanDetailVO.setSupplierName(supplierName);

        buyPlanDetailVO.setDeliveryDate(deliveryDate);

        return buyPlanDetailVO;
    }

    /**
     * @description 校验采购方式一级编码和采购方式二级编码是否正确
     * @param sheet excel的第一页
     * @param errorDetailVOList 错误信息集合
     * @param headerInfo 采购计划对象
     * @param orgId 企业编号
     * @return
     */
    private boolean checkPurchaseType( HSSFSheet sheet, List<BuyPlanReportVO> errorDetailVOList, BuyPlanVO headerInfo, String orgId )
    {
        boolean result = true;

        // 第二行第二列，取采购方式一级编码
        String firstPurchaseType = getCellValue( sheet.getRow( 1 ), 1 );
        // 第二行第四列，取采购方式二级编码
        String secondPurchaseType = getCellValue( sheet.getRow( 1 ), 3 );

        // 一级采购方式集合
        Map<String, PurchaseDictionaryDO> firstTypeMap = getFirstPurchaseType();

        // 所有一级采购方式下的二级采购方式集合
        //Map<String, PurchaseDictionaryDO> secondTypeMap = getSecondPurchaseType( firstTypeMap, orgId );

        if (StringUtil.isNullOrEmpty( firstPurchaseType ))
        {
            BuyPlanReportVO detailVO = new BuyPlanReportVO();
            detailVO.setErrorRow( 2 );
            detailVO.setRemark( "采购方式一级编码不能为空" );
            errorDetailVOList.add( detailVO );
            result = false;
        }
        else if (firstTypeMap.get( firstPurchaseType ) == null)
        {
            BuyPlanReportVO detailVO = new BuyPlanReportVO();
            detailVO.setErrorRow( 2 );
            detailVO.setRemark( "采购方式一级编码不存在" );
            errorDetailVOList.add( detailVO );
            result = false;
        }
        else
        {
            // 采购方式一级编码
            headerInfo.setTypeId( firstPurchaseType );
            // 采购方式一级名称
            headerInfo.setTypeDesc( firstTypeMap.get( firstPurchaseType ).getName() );
        }

        //根据一级编码获取改编码下的二级编码
        PurchaseDictionaryDO firstTypeDO = firstTypeMap.get(firstPurchaseType);
        PurchaseDictionaryVO param = new PurchaseDictionaryVO();
        param.setpId(firstTypeDO.getId());
        param.setOrgId(orgId);
        List<PurchaseDictionaryDO> list = purchaseDictionaryService.list(param);
        Map<String,PurchaseDictionaryDO> secondTypeMap = list.stream().collect(Collectors.toMap(PurchaseDictionaryDO::getCode,a->a,(k1,k2)->k1));

        if (!StringUtil.isNullOrEmpty( secondPurchaseType ))
        {
            if (secondTypeMap.get( secondPurchaseType ) == null)
            {
                BuyPlanReportVO detailVO = new BuyPlanReportVO();
                detailVO.setErrorRow( 2 );
                detailVO.setRemark( "采购方式二级编码不存在" );
                errorDetailVOList.add( detailVO );
                result = false;
            }
            else
            {
                // 采购方式二级编码
                headerInfo.setPurchaseTypeChildId( secondPurchaseType );
                // 采购方式二级名称
                headerInfo.setPurchaseTypeChildName( secondTypeMap.get( secondPurchaseType ).getName() );
            }
        }

        return result;
    }

    /**
     * @description <获取一级采购方式集合>
     * @return 一级采购方式集合; Key 采购方式一级编码，value：采购方式对象
     */
    private Map<String, PurchaseDictionaryDO> getFirstPurchaseType()
    {
        Map<String, PurchaseDictionaryDO> PurchaseTypeMap = new HashMap<String, PurchaseDictionaryDO>();
        // 设置查询条件
        PurchaseDictionaryVO purchaseDictionaryVO = new PurchaseDictionaryVO();
        purchaseDictionaryVO.setOrgId( "0" );

        List<PurchaseDictionaryDO> doList = purchaseDictionaryService.list( purchaseDictionaryVO );
        if (doList != null && doList.size() > 0)
        {
            for ( PurchaseDictionaryDO purchaseDict : doList )
            {
                PurchaseTypeMap.put( purchaseDict.getCode(), purchaseDict );
            }
        }

        return PurchaseTypeMap;
    }

    /**
     * @description <获取所有二级采购方式集合>
     * @return 所有二级采购方式集合; Key 采购方式二级编码，value：采购对象
     */
    private Map<String, PurchaseDictionaryDO> getSecondPurchaseType( Map<String, PurchaseDictionaryDO> firstTypeMap, String orgId )
    {
        Map<String, PurchaseDictionaryDO> PurchaseTypeMap = new HashMap<String, PurchaseDictionaryDO>();
        if (firstTypeMap == null || firstTypeMap.size() == 0)
        {
            return PurchaseTypeMap;
        }

        PurchaseDictionaryVO purchaseDictionaryVO = new PurchaseDictionaryVO();

        // 循环查询所有一级采集方式下的二级采购方式
        Iterator<String> firstKeyIter = firstTypeMap.keySet().iterator();
        while ( firstKeyIter.hasNext() )
        {
            String firstTypeCode = firstKeyIter.next();
            purchaseDictionaryVO.setOrgId( orgId );
            purchaseDictionaryVO.setpId( firstTypeMap.get( firstTypeCode ).getId() );

            // 查询二级采购方式数据
            List<PurchaseDictionaryDO> doList = purchaseDictionaryService.list( purchaseDictionaryVO );
            if (doList != null && doList.size() > 0)
            {
                for ( PurchaseDictionaryDO purchaseDict : doList )
                {
                    PurchaseTypeMap.put( purchaseDict.getCode(), purchaseDict );
                }
            }
        }

        return PurchaseTypeMap;
    }

    public void downloadBuyPlan() throws Exception
    {
        FileUtil.downLoadFile( response, filePath, buyPlanTemplateFileName );
    }

    public ErrorCode manualFinish(String billId) {
        BuyPlanDO buyPlanDO = new BuyPlanDO();
        buyPlanDO.setFinishState("2");
        buyPlanDO.setId(billId);
        buyPlanMapper.update(buyPlanDO);
        return ErrorCode.Success;
    }

    @Transactional
    public ErrorCode manualFinishDetail(String billId,String materialsNo){
        BuyPlanDetailDO buyPlanDetailDO = new BuyPlanDetailDO();
        buyPlanDetailDO.setBillId(billId);
        buyPlanDetailDO.setMaterialsNo(materialsNo);
        buyPlanDetailDO.setFinishState("1");
        buyPlanDetailMapper.update(buyPlanDetailDO);

        List<BuyPlanDetailDO> list = buyPlanDetailMapper.list(billId);
        BuyPlanDO buyPlanDO = new BuyPlanDO();
        buyPlanDO.setId(billId);
        //明细都已结单，则更新成已结单
        if (list.stream().allMatch(o->o.getFinishState() != null && "1".equals(o.getFinishState()))) {
            buyPlanDO.setFinishState("2");
        }else {//明细有未结单的，更新为部分结单
            buyPlanDO.setFinishState("1");
        }
        //需求：创建采购订单的时候如果所有未结单的零件都创建了采购订单则需要把采购计划的创建状态改为已创建（send_status=2）,如果部分创建则为部分创建
        //判断逻辑：1.如果创建了采购订单的零件行数+没有创建订单且接单的额零件行数=总行数（赋值全部创建）
        //2.否则如果创建了采购订单的零件行数为0则赋值为未创建
        //3.其他情况均为部分创建
        int allDetailNum = 0;//计划所有零件行数
        int generateNum = 0;//创建了采购订单的零件行数
        int noGeneManualFinish = 0;//没有创建订单且接单的额零件行数
        for(BuyPlanDetailDO detailDO : list){
            allDetailNum++;
            Integer isGenerate = detailDO.getIsGenerate();
            String finishState = detailDO.getFinishState();
            if(isGenerate != null && isGenerate.equals(1)){
                generateNum++;
            }else if(!StringUtils.isEmpty(finishState) && "1".equals(finishState)){
                noGeneManualFinish++;
            }
        }
        Integer sendStatus = null;
        if(generateNum+noGeneManualFinish-allDetailNum == 0){
            sendStatus = 2;
        }else if(generateNum == 0){
            sendStatus = 0;
        }else{
            sendStatus = 1;
        }
        buyPlanDO.setSendStatus(sendStatus);
        buyPlanMapper.update(buyPlanDO);
        return ErrorCode.Success;
    }
}
